
public class StConverter 
{
    private TreeNode astRoot;
    private static Boolean isTransforming;
    
    
    StConverter()
    {
        this.astRoot = null;
    }
    
    public void buildST(TreeNode astRoot) 
    {
        this.astRoot = astRoot;
        isTransforming = true;
        while(isTransforming) 
        {
            isTransforming = false;
            trans(this.astRoot);
        }
        
    }
    
    public TreeNode getSt() {
        return astRoot;
    }
    
    private void transform(TreeNode curr) {
        if (curr == null)
            return;
        
        
        if (curr.toString().equals("let"))
        {
            let(curr);
        }
        else if (curr.toString().toLowerCase().equals("where"))
        {
            where(curr);
        }
        else if (curr.toString().toLowerCase().equals("within"))
        {
            within(curr);
        }
        else if (curr.toString().toLowerCase().equals("and"))
        {
            and(curr);
        }
        else if (curr.toString().toLowerCase().equals("@"))
        {
            at(curr);
        }
        else if (curr.toString().toLowerCase().equals("function_form")
                || curr.toString().toLowerCase().equals("lambda"))
        {
            function_form(curr);
        }
        else if (curr.toString().toLowerCase().equals("rec"))
        {
            rec(curr);
        }
    }
    
    private void trans(TreeNode astCurr) // check 1
    {
        if(astCurr != null)
            transform(astCurr);
        
        if (astCurr.getExtraChild() != null) 
            transAux(astCurr);
        else 
        {
            if (astCurr.getLeftChild() != null)
                trans(astCurr.getLeftChild());
            if (astCurr.getRightChild() != null)
                trans(astCurr.getRightChild());
        }
    }
    
    private void transAux(TreeNode astCurr) {
        if (astCurr.getExtraChild() != null) 
            trans(astCurr.getExtraChild());
        if (astCurr.getLeftChild() != null) 
            transAux(astCurr.getLeftChild());
    }
    
    private void let(TreeNode curr) //check 1
    {
        if (curr.getLeftChild().getType() != NodeType.EQUALS)
            return;
        TreeNode E = curr.getLeftChild().getRightChild();
        curr.getLeftChild().setRightChild(curr.getRightChild());
        curr.setRightChild(E);
        curr.setName("gamma");
        curr.getLeftChild().setName("lambda"); 
        
        isTransforming = true;
    }
    
    private void where(TreeNode curr)
    {
        if (curr.getRightChild().getType() != NodeType.EQUALS)
            return;
                
        TreeNode P = curr.getLeftChild();
        TreeNode E = curr.getRightChild().getRightChild();
        
        curr.setLeftChild(curr.getRightChild());
        curr.setRightChild(E);
        curr.getLeftChild().setRightChild(P);
        curr.setName("gamma");
        curr.setType(NodeType.GAMMA);
        curr.getLeftChild().setName("lambda");
        curr.setType(NodeType.LAMBDA);
        isTransforming = true;
    }
    
    private void within(TreeNode curr)
    {
        if(curr.getLeftChild().getType() != NodeType.EQUALS
                || curr.getRightChild().getType() != NodeType.EQUALS)
            return;
        
        TreeNode X2 = curr.getRightChild().getLeftChild();
        TreeNode E2 = curr.getRightChild().getRightChild();
        curr.getRightChild().setLeftChild(new TreeNode());
        curr.getRightChild().setRightChild(
                curr.getLeftChild().getRightChild());
        curr.getRightChild().getLeftChild().setLeftChild(
                curr.getLeftChild().getLeftChild());
        curr.setLeftChild(X2);
        curr.getRightChild().getLeftChild().setRightChild(E2);
        curr.setType(NodeType.EQUALS);
        curr.getRightChild().setName("gamma");
        curr.getRightChild().setType(NodeType.GAMMA);
        curr.getRightChild().getLeftChild().setName("lambda");
        curr.getRightChild().getLeftChild().setType(NodeType.LAMBDA);
        
        isTransforming = true;
    }
    
    private void and(TreeNode curr) 
    {
        TreeNode head = curr;
        while(head != null)
        {
            if (head.getExtraChild().getType() != NodeType.EQUALS)
                return;
            head = head.getLeftChild();
        }
        head = curr;
        TreeNode comma = buildNode(",");
        TreeNode commaStr = comma;
        TreeNode tau = buildNode("tau");
        tau.setType(NodeType.TAU);
        TreeNode tauStr = tau;
        while(head.getLeftChild() != null)
        {
            comma.setExtraChild(
                    head.getExtraChild().getLeftChild());
            tau.setExtraChild(
                    head.getExtraChild().getRightChild());
            comma.setLeftChild(buildNode(","));
            comma.getLeftChild().setType(NodeType.COMMA);
            tau.setLeftChild(buildNode("tau"));
            tau.getLeftChild().setType(NodeType.TAU);
            comma = comma.getLeftChild();
            tau = tau.getLeftChild();
            head = head.getLeftChild();
        }
        
        comma.setExtraChild(
                head.getExtraChild().getLeftChild());
        tau.setExtraChild(
                head.getExtraChild().getRightChild());
        
        curr.setLeftChild(commaStr);
        curr.setRightChild(tauStr);
        curr.setType(NodeType.EQUALS);
        curr.setName("=");
        curr.setExtraChild(null);
        
        isTransforming = true;
    }
    
    private void rec(TreeNode curr)
    {
        if (curr.getLeftChild().getType() != NodeType.EQUALS)
            return;
        
        TreeNode E = curr.getLeftChild().getRightChild();
        curr.copy(curr.getLeftChild());
        curr.setRightChild(buildNode("gamma"));
        curr.getRightChild().setType(NodeType.GAMMA);
        curr.getRightChild().setRightChild(buildNode("lambda"));
        curr.getRightChild().getRightChild().setType(NodeType.LAMBDA);
        curr.getRightChild().setLeftChild(buildNode("Y*"));
        curr.getRightChild().getLeftChild().setType(NodeType.YSTAR);
        curr.getRightChild().getRightChild().setLeftChild(
                curr.getLeftChild());
        curr.getRightChild().getRightChild().setRightChild(E);
        
        isTransforming = true;
    }
    
    private void function_form(TreeNode curr)
    {
        if (curr.getExtraChild() == null)
            return;
        
        TreeNode lambda = buildNode("lambda");
        lambda.setType(NodeType.LAMBDA);
        TreeNode start = lambda;
        TreeNode head = curr.getLeftChild();
        while(head.getLeftChild() != null)
        {
            lambda.setRightChild(buildNode("lambda"));
            lambda.getRightChild().setType(NodeType.LAMBDA);
            lambda.setLeftChild(head.getExtraChild());
            head = head.getLeftChild();
            if(head.getLeftChild() == null)
                lambda.setRightChild(head.getExtraChild());
            lambda = lambda.getRightChild();
        }
        curr.setRightChild(start);
        if (curr.name.equals("function_form"))
            curr.setType(NodeType.EQUALS);
        curr.setLeftChild(curr.getExtraChild());
        curr.setExtraChild(null);
        
        isTransforming = true;
    }
    
    private void at(TreeNode curr)
    {
        TreeNode E1 = curr.getExtraChild();
        TreeNode N = curr.getLeftChild().getExtraChild();
        TreeNode E2 = curr.getLeftChild().getLeftChild().getExtraChild();
        
        curr.setName("gamma");
        curr.setType(NodeType.LAMBDA);
        curr.getLeftChild().setRightChild(
                curr.getLeftChild().getLeftChild());
        curr.setRightChild(E2);
        curr.getLeftChild().setRightChild(E1);
        curr.getLeftChild().setLeftChild(N);
        curr.setExtraChild(null);
        curr.getLeftChild().setExtraChild(null);
        curr.getLeftChild().setName("gamma");
        curr.getLeftChild().setType(NodeType.GAMMA);
        
        isTransforming = true;
    }

    private TreeNode buildNode(String name) 
    {
        TreeNode newNode = new TreeNode(name);
        return newNode;
    }
    
}



